home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
More Source
/
Pascal
/
Book Demos in Pascal
/
KeyConfig
/
KeyConfig.p
< prev
next >
Wrap
Text File
|
1995-04-10
|
10KB
|
377 lines
(* KeyConfig *)
(* }
{By Ingemar Ragnemalm 1995}
{This program shows a modal dialog box, in which you can select eight keys,}
{supposedly fr keyboard control for a game, plus a three-button set of radio}
{buttons and a checkbox. It also shows the key codes found for each key.}
{}
{You should study this program when making your own key configuration dialogs.}
{The most important message is that you should get the key codes through events,}
{not assume that everybody has the same key configuration as you have.}
{*)
program KeyConfig;
uses
{$ifc UNDEFINED THINK_PASCAL}
Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile, {}
GestaltEqu, Files, Errors, Packages, OSEvents,
{$endc}
Preferences;
(* Prefs record *)
type
PrefsRec = record
keyCodes: array[0..7] of char; (* Key codes *)
keyChars: array[0..7] of char; (* ASCII values *)
myRadio: Integer;
myCheckBox: Boolean;
end;
PrefsPtr = ^PrefsRec;
PrefsHnd = ^PrefsPtr;
var
gPrefs: PrefsHnd;
gTempKeyCodes: array[0..7] of char; (* Key codes, temporary stoareg while the dialog is open *)
(* The following constants must match the DLOG/DITL resource! *)
const
kHighDlogRes = 128;
kOKButton = 1;
kCancelButton = 2;
kFirstKey = 3;
kLastKey = 10;
kFirstRadio = 11;
kLastRadio = 13;
kCheckBox = 14;
kFirstCode = 15;
kLastCode = 22;
(* StdFilter *)
(* StdFilter is a dialog filter function that is useful for most}
{modal dialogs, as long as they have an OK and a Cancel button.}
{It maps return and enter to OK, and command-period and ESC to Cancel.}
{It also draws a frame around the OK button. *)
function StdFilter (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer): Boolean;
var
theChar: char;
kind: Integer;
item: Handle;
box: Rect;
begin
case theEvent.what of
keyDown:
begin
theChar := char(BAnd(theEvent.message, charCodeMask));
if ((BAnd(theEvent.modifiers, cmdKey)) <> 0) and (theChar = '.') or (theChar = char(27)) then (*cmd-. or ESC*)
begin
itemHit := kCancelButton;
(*Highlight the cancel button*)
GetDItem(theDialog, kCancelButton, kind, item, box);
HiliteControl(ControlHandle(item), 1);
StdFilter := true;
exit(StdFilter);
end;
if (theChar = char(13)) or (theChar = char(3)) then
begin
itemHit := kOKButton;
(*Highlight the OK button*)
GetDItem(theDialog, 1, kind, item, box);
HiliteControl(ControlHandle(item), kOKButton);
StdFilter := true;
exit(StdFilter);
end;
end; (*keyDown*)
updateEvt:
begin
BeginUpdate(theDialog);
SetPort(theDialog);
DrawDialog(theDialog);
(*Frame default button - item 1*)
GetDItem(theDialog, kOKButton, kind, item, box);
InsetRect(box, -4, -4);
PenSize(3, 3);
FrameRoundRect(box, 15, 15);
EndUpdate(theDialog);
end; (*update event*)
end; (*case*)
StdFilter := false;
end; (*StdFilter*)
function KeysFilter (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer): Boolean;
var
item: Integer;
theKeyNumber: Integer;
itemHandle: Handle;
itemType: Integer;
itemRect: Rect;
str: Str255;
begin
if BAnd(theEvent.modifiers, cmdKey) <> 0 then (*Command key held down*)
KeysFilter := StdFilter(theDialog, theEvent, itemHit)
else if theEvent.what <> keyDown then (*Not a keydown*)
KeysFilter := StdFilter(theDialog, theEvent, itemHit)
else if BAnd(theEvent.message, charCodeMask) = 3 then (*Enter*)
KeysFilter := StdFilter(theDialog, theEvent, itemHit)
else if BAnd(theEvent.message, charCodeMask) = 13 then (*Return*)
KeysFilter := StdFilter(theDialog, theEvent, itemHit)
else if BAnd(theEvent.message, charCodeMask) = 27 then (*Escape*)
KeysFilter := StdFilter(theDialog, theEvent, itemHit)
else if BAnd(theEvent.message, charCodeMask) = 9 then (*TAB*)
KeysFilter := StdFilter(theDialog, theEvent, itemHit)
else
(* Get the key code *)
begin
theKeyNumber := BSR(BAnd(theEvent.message, keyCodeMask), 8);
if IsDialogEvent(theEvent) then
if DialogSelect(theEvent, theDialog, item) then
begin
itemHit := item;
(* If it is one of the key boxes, put the key code in the temprary array *)
if (itemHit >= kFirstKey) and (itemHit <= kLastKey) then
begin
gTempKeyCodes[itemHit - kFirstKey] := char(theKeyNumber);
(* Just for the demo, I also display the key codes. A real game would never do that. *)
NumToString(theKeyNumber, str);
GetDItem(theDialog, itemHit - kFirstKey + kFirstCode, itemType, itemHandle, itemRect);
SetIText(itemHandle, str);
KeysFilter := true;
exit(KeysFilter);
end;
end;
end;
end; (* KeysFilter*)
(* AskKeys *)
(* This is the procedure that handles the dialog. *)
function AskKeys (prefs: PrefsHnd): Boolean;
var
theDialog: DialogPtr;
oldPort: GrafPtr;
itemHit: Integer;
itemHandle: Handle;
itemType: Integer;
itemRect: Rect;
str: Str255;
itemNo: Integer;
theFlag: Boolean;
returnValue: Boolean;
begin
returnValue := false;
GetPort(oldPort);
theDialog := GetNewDialog(kHighDlogRes, nil, WindowPtr(-1));
ShowWindow(theDialog);
SelectWindow(theDialog);
SetPort(theDialog);
(* Set all dialog items to their initial values *)
(* First set all the editable text boxes… *)
for itemNo := kFirstKey to kLastKey do
begin
GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
str[0] := char(1); (* Length 1 *)
str[1] := prefs^^.keyChars[itemNo - kFirstKey]; (* Put the char in the string *)
SetIText(itemHandle, str);
end;
(* …then the radio buttons… *)
for itemNo := kFirstRadio to kLastRadio do
begin
GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
SetCtlValue(ControlHandle(itemHandle), Integer(itemNo = prefs^^.myRadio));
end;
(* …and the checkbox… *)
GetDItem(theDialog, kCheckBox, itemType, itemHandle, itemRect);
SetCtlValue(ControlHandle(itemHandle), Integer(prefs^^.myCheckBox));
(* Finally, copy all the key codes to a temporary storage. *)
for itemNo := 0 to kLastKey - kFirstKey do
begin
gTempKeyCodes[itemNo] := prefs^^.keyCodes[itemNo];
(* Just for the demo, I also display the key codes. A real game would never do that. *)
NumToString(Longint(prefs^^.keyCodes[itemNo]), str);
GetDItem(theDialog, itemNo + kFirstCode, itemType, itemHandle, itemRect);
SetIText(itemHandle, str);
end;
(* One more thing: let the first key be selected *)
SelIText(theDialog, kFirstKey, 0, 1);
itemHit := -1;
while ((itemHit <> 1) and (itemHit <> 2)) do (* 1=ok, 2=cancel *)
begin
ModalDialog(@KeysFilter, itemHit);
(* Handle radio buttons and checkboxes here *)
if (itemHit = kCheckBox) then
begin
GetDItem(theDialog, itemHit, itemType, itemHandle, itemRect);
theFlag := Boolean(GetCtlValue(ControlHandle(itemHandle)));
SetCtlValue(ControlHandle(itemHandle), Integer(not theFlag));
end;
if (itemHit >= kFirstRadio) and (itemHit <= kLastRadio) then
for itemNo := kFirstRadio to kLastRadio do
begin
GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
SetCtlValue(ControlHandle(itemHandle), Integer(itemNo = itemHit));
end;
(* If it was a key, select it *)
if (itemHit >= kFirstKey) and (itemHit <= kLastKey) then
SelIText(theDialog, itemHit, 0, 32767);
end; (*while*)
(* If not cancelled, put the results in the prefs structure. *)
if (itemHit = 1) then
(* Get values from the dialog items *)
(* First get all the editable text boxes… *)
begin
for itemNo := kFirstKey to kLastKey do
begin
GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
GetIText(itemHandle, str);
if (str[0] <> char(0)) then (* If it's empty, leave it alone. *)
prefs^^.keyChars[itemNo - kFirstKey] := str[1];
end;
(* …then the radio buttons… *)
for itemNo := kFirstRadio to kLastRadio do
begin
GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
if Boolean(GetCtlValue(ControlHandle(itemHandle))) then
prefs^^.myRadio := itemNo;
end;
(* …and the checkbox… *)
GetDItem(theDialog, kCheckBox, itemType, itemHandle, itemRect);
prefs^^.myCheckBox := Boolean(GetCtlValue(ControlHandle(itemHandle)));
(* Finally, copy all the key codes from the temporary storage. *)
for itemNo := 0 to kLastKey - kFirstKey do
prefs^^.keyCodes[itemNo] := gTempKeyCodes[itemNo];
returnValue := true; (* OK *)
end;
;
DisposeDialog(theDialog);
SetPort(oldPort);
AskKeys := returnValue;
end; (*AskKeys*)
(*InitPrefs*)
(*This procedure loads the preferences from a resource in the current resource file,*)
(*creating a new one if there is none.*)
procedure InitPrefs;
var
i: Integer;
ignoreErr: OSErr;
begin
gPrefs := PrefsHnd(Get1Resource('Pref', 0));
if gPrefs = nil then (*Didn't exist - create it!*)
begin
gPrefs := PrefsHnd(NewHandle(sizeof(PrefsRec)));
if gPrefs = nil then
ExitToShell; (*Insert error message here*)
(* We should fill it with some values here *)
AddResource(Handle(gPrefs), 'Pref', 0, 'Preferences');
end
else (*Did exist - check the size!*)
if (GetHandleSize(Handle(gPrefs)) < sizeof(PrefsRec)) then
SetHandleSize(Handle(gPrefs), sizeof(PrefsRec));
end; (*InitScores*)
(* Standard inits *)
procedure InitToolbox;
begin
{$ifc UNDEFINED THINK_PASCAL}
InitGraf(@qd.thePort);
InitFonts;
FlushEvents(everyEvent, 0);
InitWindows;
InitMenus;
TEInit;
InitDialogs(nil);
{$endc}
InitCursor;
end;
(****************** Main program ******************)
var
str: Str255;
i: Integer;
gAppFile, gPrefFile: Integer;
begin
InitToolbox;
(*Get the prefs file - create as necessary.*)
if SetPrefFile('KeyConfig Preferences', '????', 'pref', gAppFile, gPrefFile) then
;
(*Set the current resource file to the preference file before InitScores*)
if gPrefFile <> 0 then
UseResFile(gPrefFile);
InitPrefs;
UseResFile(gAppFile);
if AskKeys(gPrefs) then
begin
ChangedResource(Handle(gPrefs));
WriteResource(Handle(gPrefs));
end;
CloseResFile(gPrefFile);
end. (*KeyConfig*)